---
title: Monitor the network state to reduce latency
---

<ExperimentalFeature>

**Network Monitor APIs are currently [experimental](https://www.apollographql.com/docs/resources/product-launch-stages/#experimental-features) in Apollo Kotlin.** If you have feedback on them, please let us know via [GitHub issues](https://github.com/apollographql/apollo-kotlin/issues/new?assignees=&labels=Type%3A+Bug&template=bug_report.md) or in the [Kotlin Slack community](https://slack.kotl.in/).

</ExperimentalFeature> 

Android and Apple targets provide APIs to monitor the network state of your device:

- [ConnectivityManager](https://developer.android.com/training/monitoring-device-state/) on Android targets.
- [NWPathMonitor](https://developer.apple.com/documentation/network/nwpathmonitor) on Apple targets.

You can configure your [ApolloClient](https://www.apollographql.com/docs/kotlin/kdoc/apollo-runtime/com.apollographql.apollo/-apollo-client/index.html) to use these APIs to improve latency of your requests using the `NetworkMonitor` API:

```kotlin
// androidMain
val networkMonitor = NetworkMonitor(context)

// appleMain
val networkMonitor = NetworkMonitor()

// commonMain
val apolloClient = ApolloClient.Builder()
    .serverUrl("https://example.com/graphql")
    .retryOnErrorInterceptor(RetryOnErrorInterceptor(networkMonitor))
    .build()

// once you're done with your `ApolloClient`
networkMonitor.close()
```

### `failFastIfOffline`

When a `NetworkMonitor` is configured, you can use `failFastIfOffline` to avoid trying out request if the device is offline:

```kotlin
// Opt-in `failFastIfOffline` on all queries
val apolloClient = ApolloClient.Builder()
    .serverUrl("https://example.com/graphql")
    .failFastIfOffline(true)
    .build()

val response = apolloClient.query(myQuery).execute()
println(response.exception?.message)
// "The device is offline"

// Opt-out `failFastIfOffline` on a single query
val response = apolloClient.query(myQuery).failFastIfOffline(false).execute()
```

### `retryOnError`

When a `NetworkMonitor` is configured, `retryOnError` uses `NetworkMonitor.waitForNetwork()` instead of the default exponential backoff algorithm in order to reconnect faster when connectivity is back.

### Customizing the retry algorithm

You can customize the retry algorithm further by defining your own interceptor:

```kotlin
val apolloClient = ApolloClient.Builder()
    .retryOnErrorInterceptor(MyRetryOnErrorInterceptor())
    .build()

class MyRetryOnErrorInterceptor : ApolloInterceptor {
  object RetryException : Exception()

  override fun <D : Operation.Data> intercept(request: ApolloRequest<D>, chain: ApolloInterceptorChain): Flow<ApolloResponse<D>> {
    var attempt = 0
    return chain.proceed(request).onEach {
      if (request.retryOnError == true && it.exception != null && it.exception is ApolloNetworkException) {
        throw RetryException
      } else {
        attempt = 0
      }
    }.retryWhen { cause, _ ->
      if (cause is RetryException) {
        attempt++
        delay(2.0.pow(attempt).seconds)
        true
      } else {
        // Not a RetryException, probably a programming error, pass it through
        false
      }
    }
  }
}
```

